﻿#include "IPluginDialog.h"
#include <QTranslator>
#include <QMetaProperty>
#include <QMetaObject>
#include <QDebug>
#include <QFrame>
#include <QLabel>
#include <QPushButton>
#include <QApplication>
#include <QJsonObject>
#include <QJsonValue>
#include <QVBoxLayout>
#include <QScrollArea>

#include "GraphicWidgetModel.h"
#include "ImageResultPreviewWidget.h"
#include "IAlgorithmPluginOperator.h"
#include "IAlgorithmPluginParam.h"
#include "AbstractEntity.h"
#include "IFlowTreeManager.h"
#include "ISignalBridge.h"
#include "AbstractEntity.h"
#include "Circular.h"

using CVV::Infrastructure::View::ImageResultPreviewWidget;
using namespace CVV::Interface;
using CVV::Entity::Circular;

IPluginDialog::IPluginDialog(const QString &pluginCode,
                             const QString &flowId,
                             const QString &cellId,
                             const QString &cellTitle,
                             QWidget *parent)
    : QDialog(parent)
    , m_flowId(flowId)
    , m_cellId(cellId)
    , m_cellTitle(cellTitle)
    , m_pluginCode(pluginCode)
{
    m_title = cellTitle;
    this->setWindowFlags(Qt::FramelessWindowHint);

    initPlugin();
    m_translator = nullptr;
    setMinimumSize(800,600);
    m_paintModel = std::make_shared<GraphicWidgetModel>(this);

    connectSignalSlots();
}

IPluginDialog::~IPluginDialog()
{
    if(m_translator)
    {
        delete m_translator;
    }
    qDebug() << __func__;
}

QMap<QString, QList<FlowCellParam> > IPluginDialog::getPrevOutFlowParam(const QString &dataType)
{
    QMap<QString, QList<FlowCellParam>> flowcellparamMaps;
    QList<FlowTree> lstPreFlowTree = gFlowTreeManager->getPrevOutFlowTree(m_flowId, m_cellId);
    for (auto flowtree : qAsConst(lstPreFlowTree))
    {
        std::shared_ptr<IPluginDialog> cell = IPluginOperator::getFlowCellDialog(flowtree.pluginCode(), m_flowId, flowtree.cellId());
        if (!cell)
        {
            continue;
        }

        QList<FlowCellParam> flowCellParams;
        QJsonArray aryPluginParam = gFlowTreeManager->getPluginParam(m_flowId, flowtree.cellId(), flowtree.pluginCode());
        for( auto param : aryPluginParam)
        {
            QJsonObject pobj = param.toObject();
            FlowCellParam fcp;
            const QMetaObject* metaObj = fcp.metaObject();
            int propertyCnt = metaObj->propertyCount();
            for ( int i = 1; i < propertyCnt; ++i )
            {
                QMetaProperty oneProperty = metaObj->property(i);
                QString properyName = oneProperty.name();
                if(properyName == "Value")
                {
                    QString code = pobj.value("Code").toString();
                    QVariant var = cell->getPluginParam()->property(code.toStdString().c_str());
                    if (var.canConvert<QList<std::shared_ptr<CVV::Entity::AbstractEntity>>>())
                    {
                        QList<std::shared_ptr<CVV::Entity::AbstractEntity>> lstVar = var.value<QList<std::shared_ptr<CVV::Entity::AbstractEntity>>>();
                        QStringList lstStr;
                        for (auto &val : qAsConst(lstVar))
                        {
                            if (!val)
                            {
                                continue;
                            }

                            QString str = val->toString();
                            if (!str.isEmpty())
                            {
                                lstStr.push_back(str);
                            }
                        }
                        lstVar.clear();
                        fcp.setValue(lstStr.join(","));
                    }
                    else
                    {
                        fcp.setValue(var.toString());
                    }
                }
                else
                {
                    QString val = pobj.value(properyName).toString();
                    fcp.setProperty(oneProperty.name(), val);
                }
            }
            fcp.setPluginCode(flowtree.pluginCode());
            fcp.setPluginId(flowtree.cellId());
            if(fcp.paramType() != "Out")
            {
                continue;
            }

            if(dataType.isEmpty())
            {
                flowCellParams.append(fcp);
            }
            else if(!dataType.isEmpty() && fcp.type() == dataType)
            {
                flowCellParams.append(fcp);
            }
        }

        flowcellparamMaps.insert(QString("%1_%2").arg(flowtree.pluginName()).arg(flowtree.cellId()), flowCellParams);
    }

    // 传入子流程的参数
    for (auto itr = m_hashSubprocessInputParam.begin(); itr != m_hashSubprocessInputParam.end(); ++itr)
    {
        QList<FlowCellParam> lstFlowCellParams;
        for (auto param : (*itr))
        {
            if (param.code() != "InputValues")
            {
                    continue;
            }

            QVariant var = param.userTypeValue();
            if (var.isValid() && var.canConvert<QList<std::shared_ptr<CVV::Entity::AbstractEntity>>>())
            {
                QList<std::shared_ptr<CVV::Entity::AbstractEntity>> lstEntity = var.value<QList<std::shared_ptr<CVV::Entity::AbstractEntity>>>();
                for (auto entity : lstEntity)
                {
                    std::shared_ptr<CVV::Entity::MapVariable> pVariable = std::dynamic_pointer_cast<CVV::Entity::MapVariable>(entity);
                    if (pVariable)
                    {
                        FlowCellParam fcp;
                        fcp.setType(pVariable->getVarType());
                        fcp.setCode(pVariable->getVarName());
                        fcp.setName(pVariable->getVarName());
                        fcp.setValue(pVariable->getVarValue());
                        fcp.setPluginCode(param.pluginCode());
                        fcp.setPluginId(param.pluginId());
                        lstFlowCellParams.push_back(fcp);
                    }
                }
            }
        }
        if (!lstFlowCellParams.isEmpty())
        {
            flowcellparamMaps.insert(itr.key(), lstFlowCellParams);
        }
    }

    return flowcellparamMaps;
}

void IPluginDialog::findAllPreOutFlowTree(const QList<FlowTree> &lstAllFlowTree, const FlowTree &paFlowTree, QList<FlowTree> &lstPreFlowTree)
{
    QString strPreId = paFlowTree.preCellId();
    if (strPreId == paFlowTree.cellId())
    {
        return;
    }

    QStringList lstPreId = strPreId.split(",");
    for (auto flowTree : qAsConst(lstAllFlowTree))
    {
        if (lstPreId.contains(flowTree.cellId()))     // 上级节点和上级节点的子节点
        {
            lstPreFlowTree.append(flowTree);
            findAllPreOutFlowTree(lstAllFlowTree, flowTree, lstPreFlowTree);
        }
    }
}


QList<FlowCellParam> IPluginDialog::getFlowCellParam()
{
    QList<FlowCellParam> flowCellParams;
    QJsonArray aryPluginParam = gFlowTreeManager->getPluginParam(m_flowId, m_cellId, m_pluginCode);
    for( auto param : aryPluginParam)
    {
        QJsonObject pobj = param.toObject();
        FlowCellParam fcp;
        const QMetaObject* metaObj = fcp.metaObject();
        if (!metaObj)
        {
            continue;
        }

        int propertyCnt = metaObj->propertyCount();
        for ( int i = 1; i < propertyCnt; ++i )
        {
            QMetaProperty oneProperty = metaObj->property(i);
            QString properyName=oneProperty.name();
            if("Value" == properyName)
            {
                QString code=pobj.value("Code").toString();
                QString sValue;
                QVariant var = getPluginParam()->property(code.toStdString().c_str());
                if (var.canConvert<QList<std::shared_ptr<CVV::Entity::AbstractEntity>>>())
                {
                    QList<std::shared_ptr<CVV::Entity::AbstractEntity>> lstValue = var.value<QList<std::shared_ptr<CVV::Entity::AbstractEntity>>>();
                    lstValue.clear();
                    continue;
                }
                QVariant::Type ty = var.type();
                if(ty == QVariant::PointF)
                {
                    QPointF point= var.value<QPointF>();
                    sValue = QString("%1,%2").arg(point.x()).arg(point.y());
                }
                else if(ty == QVariant::RectF)
                {
                    QRectF rect= var.value<QRectF>();
                    sValue = QString("%1,%2,%3,%4").arg(rect.x()).arg(rect.y()).arg(rect.width()).arg(rect.height());
                }
                else if(ty == QVariant::StringList)
                {
                    QStringList vec = var.value<QStringList>();
                    sValue = vec.join(",");
                }
                else if(ty == QVariant::Bool)
                {
                    sValue = var.toString();
                }
                else
                {
                    sValue = var.toString();
                }
                fcp.setValue(sValue);
            }
            else if ("UserTypeValue" == properyName)
            {
                QString code = pobj.value("Code").toString();
                QVariant var = getPluginParam()->property(code.toStdString().c_str());
                QVariant::Type ty = var.type();
                if (ty == QVariant::UserType)
                {
                    fcp.setUserTypeValue(var);
                }
            }
            else if("PluginCode" == properyName)
            {
                fcp.setPluginCode(m_pluginCode);
            }
            else if("PluginID" == properyName)
            {
                fcp.setPluginId(m_cellId);
            }
            else
            {
                fcp.setProperty(oneProperty.name(),pobj.value(properyName).toString());
            }
        }
        flowCellParams.push_back(fcp);
    }

    return flowCellParams;
}

QList<FlowCellParam> IPluginDialog::getFlowCellAlgorithmParam()
{
    QList<FlowCellParam> flowCellParams;
    auto obj = PluginManager::getObjectByName(getPluginParam()->getAlgoritmPluginCode());
    IAlgorithmPluginOperator *opt = dynamic_cast<IAlgorithmPluginOperator*>(obj);
    if (!opt)
    {
        return flowCellParams;
    }
    std::shared_ptr<IAlgorithmPluginParam> pAlgParam = opt->getAlgorithmPluginParam(m_flowId, getPluginParam()->getT_id());
    if (!pAlgParam)
    {
        return flowCellParams;
    }

    QJsonArray algPluginParams = gFlowTreeManager->getPluginParam(m_flowId, m_cellId, opt->objectName());
    for( auto param : algPluginParams)
    {
        QJsonObject pobj = param.toObject();
        FlowCellParam fcp;
        const QMetaObject* metaObj = fcp.metaObject();
        int propertyCnt = metaObj->propertyCount();
        for ( int i = 1; i < propertyCnt; ++i )
        {
            QMetaProperty oneProperty = metaObj->property(i);
            QString properyName = oneProperty.name();
            if(properyName == "Value")
            {
                QString code = pobj.value("Code").toString();
                QString sValue;
                QVariant::Type ty = pAlgParam->property(code.toStdString().c_str()).type();

                if(ty == QVariant::PointF)
                {
                    QPointF point= pAlgParam->property(code.toStdString().c_str()).value<QPointF>();
                    sValue = QString("%1,%2").arg(point.x()).arg(point.y());
                }
                else if(ty == QVariant::RectF)
                {
                    QRectF rect= pAlgParam->property(code.toStdString().c_str()).value<QRectF>();
                    sValue = QString("%1,%2,%3,%4").arg(rect.x()).arg(rect.y()).arg(rect.width()).arg(rect.height());
                }
                else if(ty == QVariant::StringList)
                {
                    QStringList vec= pAlgParam->property(code.toStdString().c_str()).value<QStringList>();
                    sValue = vec.join(",");
                }
                else
                {
                    sValue =  pAlgParam->property(code.toStdString().c_str()).toString();
                }

                fcp.setValue(sValue);
            }
            else if ("UserTypeValue" == properyName)
            {
                QString code = pobj.value("Code").toString();
                QVariant var = pAlgParam->property(code.toStdString().c_str());
                QVariant::Type ty = var.type();
                if (ty == QVariant::UserType
                        || ty == QVariant::Point)
                {
                    fcp.setUserTypeValue(var);
                }
            }
            else
            {
                fcp.setProperty(oneProperty.name(), pobj.value(properyName).toString());
            }
        }
        flowCellParams.push_back(fcp);
    }

    return flowCellParams;
}

QMap<QString, QList<FlowCellParam> > IPluginDialog::getFlowParam()
{
    QMap<QString, QList<FlowCellParam>> flowcellparamMaps;
    QMap<QString, FlowTree> flowtreeMap = getFlowTree();
    for (auto flowtree : flowtreeMap.values())
    {
        auto obj = PluginManager::getObjectByName(flowtree.pluginCode());
        IPluginOperator *opt = dynamic_cast<IPluginOperator *>(obj);
        if(!opt)
        {
            continue;
        }
        QMap<QString, QMap<QString, std::shared_ptr<IPluginDialog>>> flowPDMap =
                opt->flowCellDialogs();
        if(flowPDMap.contains(m_flowId) && flowPDMap[m_flowId].contains(flowtree.cellId()))
        {
            std::shared_ptr<IPluginDialog> cell = flowPDMap[m_flowId][flowtree.cellId()];
            QList<FlowCellParam> flowCellParams;
            for( auto param : m_pluginParams[opt->objectName()]){

                QJsonObject pobj = param.toObject();
                FlowCellParam fcp;
                const QMetaObject* metaObj = fcp.metaObject();
                int propertyCnt = metaObj->propertyCount();
                for ( int i = 1; i < propertyCnt; ++i )
                {
                    QMetaProperty oneProperty = metaObj->property(i);
                    QString properyName = oneProperty.name();
                    if(properyName == "Value")
                    {
                        QString code = pobj.value("Code").toString();
                        QVariant var = cell->getPluginParam()->property(code.toStdString().c_str());
                        if (var.canConvert<QList<std::shared_ptr<CVV::Entity::AbstractEntity>>>())
                        {
                            QStringList lstStr;
                            QList<std::shared_ptr<CVV::Entity::AbstractEntity>> lstValue = var.value<QList<std::shared_ptr<CVV::Entity::AbstractEntity>>>();
                            for (auto &val : qAsConst(lstValue))
                            {
                                if (!val)
                                {
                                    continue;
                                }

                                QString str = val->toString();
                                if (!str.isEmpty())
                                {
                                    lstStr.push_back(str);
                                }
                            }
                            lstValue.clear();
                            fcp.setValue(lstStr.join(","));
                        }
                        else
                        {
                            fcp.setValue(var.toString());
                        }
                    }
                    else
                    {
                        QString val=pobj.value(properyName).toString();
                        fcp.setProperty(oneProperty.name(),val);
                    }
                }
                fcp.setPluginCode(flowtree.pluginCode());
                fcp.setPluginId(flowtree.cellId());
                flowCellParams.append(fcp);

            }
            flowcellparamMaps.insert(QString("%1_%2").arg(flowtree.pluginName()).arg(flowtree.cellId()) ,flowCellParams);
        }
    }
    return  flowcellparamMaps;
}

QList<Circular> IPluginDialog::getListCircleFromParamData(const QString &pluginParamPath)
{
    QList<Circular> value;
    value.clear();
    QStringList paths= pluginParamPath.split(".");
    if(3 <= paths.size())
    {
        QString pluginCode = paths[0];
        QString cellId = paths[1];
        QString paramName = paths[2];
        auto obj = PluginManager::getObjectByName(pluginCode);
        IPluginOperator *opt = dynamic_cast<IPluginOperator *>(obj);
        if(opt != nullptr)
        {
            QMap<QString,QMap<QString, std::shared_ptr<IPluginDialog>>> flowPDMap= opt->flowCellDialogs();
            if(flowPDMap.contains(m_flowId) && flowPDMap[m_flowId].contains(cellId))
            {
                IPluginParam* param = flowPDMap[m_flowId][cellId]->getPluginParam();
                if (param)
                {
                    value = param->getActuralDetectCircle();
                }
            }
        }
    }
    return  value;
}

void IPluginDialog::setDynamicParamDefine(const QList<std::tuple<QString, QString, QString>> &pairList)
{
    QList<FlowCellParam> params;
    for(auto p : pairList)
    {
        QString sType = std::get<0>(p);
        QString sCode = std::get<1>(p);
        QString sValue = std::get<2>(p);
        QVariant var = sValue;
        if (0 == sType.compare("int", Qt::CaseInsensitive))
        {
            var = sValue.toInt();
        }
        else if (0 == sType.compare("double", Qt::CaseInsensitive))
        {
            var = sValue.toDouble();
        }
        else if (0 == sType.compare("float", Qt::CaseInsensitive))
        {
            var = sValue.toFloat();
        }
        FlowCellParam flowCellParam;
        flowCellParam.setCode(sCode);
        flowCellParam.setParamType("Out");
        flowCellParam.setIsSave("true");
        flowCellParam.setPluginCode(m_pluginCode);
        flowCellParam.setPluginId(m_flowId);
        flowCellParam.setType(sType);
        flowCellParam.setName(sCode);
        params.append(flowCellParam);
        getPluginParam()->setProperty(sCode.toStdString().c_str(), var);
    }

    QString key = QString("%1_%2").arg(m_pluginCode).arg(m_cellId);
    PluginManager::removePluginParam(key);
    QJsonArray array;
    for( auto param : params)
    {
        QJsonObject object;
        const QMetaObject* metaObj = param.metaObject();
        int propertyCnt = metaObj->propertyCount();
        for ( int i = 1; i < propertyCnt; ++i )
        {
            QMetaProperty oneProperty = metaObj->property(i);
            QString properyName = oneProperty.name();

            object.insert(properyName,param.property(properyName.toStdString().c_str()).toString());
        }
        array.append(object);
    }
    PluginManager::addPluginParam(key,array);
    initPlugin();
}

bool IPluginDialog::initPlugin()
{
    QMap<QString, QJsonArray> dynamic = PluginManager::pluginParams();
    for(auto dynamicKey : dynamic.keys())
    {
        QStringList lstStr = dynamicKey.split("_");
        if (lstStr.size() != 2
                || lstStr.last() != m_cellId
                || lstStr.first() != m_pluginCode)
        {
            continue;
        }

        gFlowTreeManager->updateDynamicParam(m_flowId, m_cellId, m_pluginCode, dynamic[dynamicKey]);
    }

    return  true;
}

void IPluginDialog::connectSignalSlots()
{
    connect(CVV::Interface::ISignalBridge::instance(), &Interface::ISignalBridge::sigDefectImportSuccess,
            this, &IPluginDialog::setDefectPinYinCode);
    connect(CVV::Interface::ISignalBridge::instance(), &Interface::ISignalBridge::sigChangeLanguage,
            this, &IPluginDialog::changeLanguage);

    connect(CVV::Interface::ISignalBridge::instance(), &Interface::ISignalBridge::sigUpdateSubprocessFlowTree,
            this, &IPluginDialog::slotUpdateSubprocessFlowTree);
    connect(this, &IPluginDialog::finished, this, &IPluginDialog::sigClose);

}

QMap<QString, FlowTree> IPluginDialog::getFlowTree() const
{
    return m_flowTree;
}

void IPluginDialog::setFlowTree(const QMap<QString, FlowTree> &flowTree)
{
    m_flowTree = flowTree;
    initPlugin();
    updatedDom();
}

void IPluginDialog::closeEvent(QCloseEvent *e)
{
    emit sigClose();
    emit sigSendModelToMainWin(m_paintModel);
    e->ignore();
//    QDialog::closeEvent(e);
}

void IPluginDialog::showEvent(QShowEvent *e)
{
    QDialog::showEvent(e);
    if(getGraphicWidgetPtr())
    {
        ImageResultPreviewWidget * imagWidget = static_cast<ImageResultPreviewWidget *>(getGraphicWidgetPtr());
        if(imagWidget)
        {
            imagWidget->restoreClicked();
        }
    }
}

QWidget *IPluginDialog::pluginHelpPage()
{
    PluginSpec* pSpec = PluginManager::getPluginSpecByCode(m_pluginCode);
    QFrame *pFrame = new QFrame(this);
    QScrollArea *pScrollArea = new QScrollArea(pFrame);
    QLabel* pLabelDescription = new QLabel(pScrollArea);
    pScrollArea->setContextMenuPolicy(Qt::NoContextMenu);
    pScrollArea->setWidgetResizable(true);
    pScrollArea->setWidget(pLabelDescription);
    pScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    pLabelDescription->setAlignment(Qt::AlignLeft | Qt::AlignTop);
    pLabelDescription->setWordWrap(true);
    if (pSpec)
    {
        // 显示帮助信息
        pLabelDescription->setText(pSpec->description().trimmed());
    }

    QVBoxLayout* pMainLayout = new QVBoxLayout(pFrame);
    pMainLayout->addWidget(pScrollArea);
    pFrame->setLayout(pMainLayout);

    return pFrame;
}


QMap<QString, QJsonArray> IPluginDialog::getPluginParams() const
{
    return m_pluginParams;
}

void IPluginDialog::setToolName(const QString &name)
{
    m_strToolName = name;
}

void IPluginDialog::setDefectPinYinCode(const QStringList &lstCode)
{
    m_lstDefectPinYinCode = lstCode;
}

void IPluginDialog::setSubprocessFlowCellParam(const QHash<QString, QList<FlowCellParam> > &mapData)
{
    m_hashSubprocessFlowCellParam = mapData;
}

void IPluginDialog::setSubprocessInputParam(const QHash<QString, QList<FlowCellParam> > &hashData)
{
    m_hashSubprocessInputParam = hashData;
}

void IPluginDialog::setSubprocessParamValue(const QMap<QString, QVariant> &mapData)
{
    m_mapSubprocessParamValue = mapData;
}

void IPluginDialog::slotUpdateSubprocessFlowTree(const QString &flowId, const QString &cellId, const QString &subFlowId)
{
    if (flowId != m_flowId
            || cellId != m_cellId)
    {
        return;
    }

    qDebug() << __FUNCTION__ << "flowId = " << flowId << ", cellId = " << cellId << ", subFlowId = " << subFlowId
             << ", m_flowId = " << m_flowId << ", m_cellId = " << m_cellId;

    m_strSubFlowId = subFlowId;
    QHash<QString, QList<FlowCellParam>> hashParam = Interface::IPluginOperator::getFlowTreeParams(subFlowId);

    // 筛选输出参数
    m_hashSubprocessFlowCellParam.clear();
    for (auto itr = hashParam.begin(); itr != hashParam.end(); ++itr)
    {
        for (auto param : (*itr))
        {
            if (0 == param.paramType().compare("Out", Qt::CaseInsensitive))
            {
                m_hashSubprocessFlowCellParam[itr.key()].push_back(param);
            }
        }
    }
}

